#include "stdafx.h"
#include "ActiveObjectTestSuite.h"

using namespace CO::SpiFoundation::RoomFW;
using namespace CO::MyGroupNamespace::MyPackageNamespace;

ActiveObjectTestSuite::ActiveObjectTestSuite()
{
	TEST_ADD(ActiveObjectTestSuite::Main);
}

ActiveObjectTestSuite::~ActiveObjectTestSuite()
{
}

void ActiveObjectTestSuite::setup()
{
	//
	// Track initialization errors.
	//
	initialized_ = true;
	errorMessage_.clear();
	testComplete_ = false;
	responseCount_ = 0;

	try
	{
		// Initialize the logger.
		//G_LOGGER.setConsole(true, 512);
		G_LOGGER.setFile(true, "ActiveObjectTestSuite.log");
		if (!G_LOGGER.start())
		{
			throw "Failed to start logger";
		}

		// Create the test object.
		activeObject_ = MyActiveInterface::Create(MyActiveInterface::MY_ACTIVE_OBJECT_CONTAINER);
		if (!activeObject_)
		{
			throw "Failed to create test object";
		}

		// Create portals.
		systemManagerPortal_.reset(new CallbackPortal("SystemManagerPortal", &portalQueue_));
		if (!systemManagerPortal_)
		{
			throw "Failed to create SystemManagerPortal";
		}
		activeObjectPortal_.reset(new CallbackPortal("ActiveObjectPortal", &portalQueue_)); 
		if (!activeObjectPortal_)
		{
			throw "Failed to create ActiveObjectPortal.";
		}

		//
		// Bind portals.
		//
		bindingList_.push_back(
			PortalBindingSP( new PortalBinding(
				systemManagerPortal_, 
				activeObject_, 
				MyActiveInterface::PORT_MY_PORT_3)));

		bindingList_.push_back(
			PortalBindingSP( new PortalBinding(
				activeObjectPortal_, 
				activeObject_, 
				MyActiveInterface::PORT_MY_PORT_1)));
	
		//
		// Initialize Test Object.
		//
		CO::SpiFoundation::Configuration::ConfigKey configRoot =
			IConfigFileReg::Instance().getDefaultConfig();
		configRoot.setValue_T(CFG_VAL_PATH_MyIntValue, 1L);
		if (!activeObject_->initialize(configRoot))
		{
			throw "Failed to initialize test object";
		}

		//
		// Start Test Object.
		//
		if (!activeObject_->start())
		{
			throw "Failed to start test object";
		}
	}
	catch (std::runtime_error e)
	{
		initialized_ = false;
		errorMessage_ = e.what();
	}
	catch (const char* e)
	{
		initialized_ = false;
		errorMessage_ = e;
	}
	catch (...)
	{
		initialized_ = false;
		errorMessage_ = "Unhandled exception";
	}
}

void ActiveObjectTestSuite::tear_down()
{
	// Stop test object.
	if (0 != activeObject_)
	{
		VERIFY(activeObject_->stop());
	}

	// Clear bindings.
	bindingList_.clear();

	// Clear Portal Queue.
	while (portalQueue_.pop())
		; // just pop until it returns null.

	// Delete all test objects.
	systemManagerPortal_.reset();
	activeObjectPortal_.reset();
	activeObject_.reset();

	// Stop the logger.
	VERIFY(G_LOGGER.stop());
}

bool ActiveObjectTestSuite::handleSystemPort(RoomMessageSP message)
{
	bool retVal = (MyProtocol::I_AM_READY_ACK == message->messageID());
	if (retVal)
	{
		++responseCount_;
		IPayloadSP sndData(new MyPayload(42.42));
		activeObjectPortal_->sendMessage(MyProtocol::IN_MESSAGE_1, IPayload::ReleaseOwnership(sndData));
	}
	return retVal;
}

bool ActiveObjectTestSuite::handlePort1(RoomMessageSP message)
{
	bool retVal = (MyProtocol::OUT_MESSAGE_1 == message->messageID());
	if (retVal)
	{
		MyPayloadSP rcvData = ::boost::static_pointer_cast<MyPayload, IPayload>(message->payload());
		retVal = (42.42 == rcvData->value());
		if (!retVal)
		{
			errorMessage_ = "Wrong payload value";
		}
		else if (++responseCount_ >= 3)
		{
			testComplete_ = true;
		}
	}
	else
	{
		errorMessage_ = "Wrong message received on port1";
	}
	return retVal;
}

void ActiveObjectTestSuite::Main()
{
	//
	// Check initialization.
	//
	TEST_ASSERT_MSG(initialized_, errorMessage_.c_str());
	try
	{
		//
		// Start the test.
		//
		systemManagerPortal_->sendMessage(MyProtocol::I_AM_READY);

		//
		// Loop to process portal messages.
		//
		while (!testComplete_ && portalQueue_.wait(DWait))
		{
			//
			// Get portal and message.
			//
			CallbackPortal* portal = portalQueue_.pop();
			TEST_ASSERT(0 != portal); // since we waited for it.
			RoomMessageSP message = portal->getMessage();
			TEST_ASSERT(0 != message); // since we waited for it.

			//
			// Process message based on portal.
			//
			if (systemManagerPortal_.get() == portal)
			{
				TEST_ASSERT_MSG(this->handleSystemPort(message), errorMessage_.c_str());
			}
			else if (activeObjectPortal_.get() == portal)
			{
				TEST_ASSERT_MSG(this->handlePort1(message), errorMessage_.c_str());
			}
		}
		TEST_ASSERT_MSG(testComplete_, "Timeout waiting for message from Test Object");
	}
	catch (std::exception& e)
	{
		G_LOG_0_ERROR(e.what());
		TEST_FAIL(e.what());
	}
}
